import string
import random
import urllib.parse
import datetime
from rest_framework import serializers
from wechatpy.exceptions import WeChatPayException
from .models import WxPayOrder
from finance_c2c.local_settings import Config, miniNoticePayUrl
from .WXInstance import KLBWxPay
from core.tools.func_utils import funcUtils
from finance_c2c.local_settings import KaLaiBaoConfig
from chinese_calendar import is_workday

orderModel = (("czb", "车主邦加油"), ("coffee", "coffee"),)


# 微信支付基础类
class BasePaySerializer(serializers.Serializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    orderNo = serializers.CharField(required=True, allow_null=False, label="订单号", help_text="订单号", write_only=True)
    model = serializers.CharField(required=True, allow_null=False, label="model", help_text="model",
                                  write_only=True)

    wxPayInstance = None
    payData = None

    def wx_pay_instance(self):
        assert self.wxPayInstance is not None, (
            "%s 必须包含`wxPayInstance`属性, 或者重写wx_pay_instance方法" % self.__class__.__name__
        )
        return self.wxPayInstance

    def pay_data(self):
        assert isinstance(self.payData, dict), (
            "%s 必须包含`payData`属性, pay_data" % self.__class__.__name__
        )
        data_keys = list(self.payData.keys())
        base_keys = ["noticePayUrl", "body", "total_fee", "openid", "trade_type", "mch_id"]
        data_keys.sort()
        base_keys.sort()
        if "attach" in data_keys:
            data_keys.remove("attach")
        assert not set(base_keys).difference(set(data_keys)), (
            "%s 的`payData`属性, 必须包含%r这些keys" % (self.__class__.__name__, base_keys)
        )
        return self.payData

    def validate_model(self, model):
        if model == "coffee":
            return model
        else:
            raise serializers.ValidationError("参数错误")

    @property
    def make_out_trade_no(self):
        value = funcUtils.unique_value
        s = string.ascii_letters
        r = random.sample(s, 11)
        v = value + "".join(r)
        return v

    def get_out_trade_no(self, order):
        if order.out_trade_no:
            out_trade_no = order.out_trade_no
            if WxPayOrder.objects.filter(out_trade_no=out_trade_no).exists():
                pay_record = WxPayOrder.objects.get(out_trade_no=out_trade_no)
                if pay_record.is_pay:
                    raise serializers.ValidationError("此订单已经支付成功")
                last_num = out_trade_no[-1]
                if last_num == "9":
                    raise serializers.ValidationError("此订单已经锁定，请重新下单")
                if last_num.isdigit():
                    last_num = str(int(last_num) + 1)
                    n = 1
                else:
                    n = 0
                    last_num = "0"
                out_trade_no = out_trade_no[:len(out_trade_no) - n] + last_num
        else:
            out_trade_no = self.make_out_trade_no
        return out_trade_no

    def validate_orderNo(self, orderNo):
        model = self.initial_data["model"]
        if model == "coffee":
            from apps.coffee.models import CoffeeOrder
            try:
                order = CoffeeOrder.objects.get(orderNo=orderNo)
            except Exception as e:
                print(e, orderNo, "微信支付咖啡机订单号")
                raise serializers.ValidationError("订单号错误")
            if order.result != 0:
                raise serializers.ValidationError("此订单不可以再发起支付")
        else:
            raise serializers.ValidationError("参数错误")

        order.out_trade_no = self.get_out_trade_no(order)
        order.save()
        return order

    def create(self, validated_data):
        pay_data_value = self.pay_data()
        print(pay_data_value, "pay_data_value")
        noticePayUrl = pay_data_value.get("noticePayUrl")
        body = pay_data_value.get("body")
        total_fee = pay_data_value.get("total_fee")
        openid = pay_data_value.get("openid")
        trade_type = pay_data_value.get("trade_type")
        mch_id = pay_data_value.get("mch_id")
        attach = pay_data_value.get("attach")
        wxPay = self.wx_pay_instance()
        model = validated_data["model"]
        order = validated_data["orderNo"]
        out_trade_no = order.out_trade_no
        print(out_trade_no, "out_trade_no")
        wx_order_instance = WxPayOrder.objects.create(
            out_trade_no=out_trade_no,
            total_fee=total_fee,
            trade_type=trade_type,
            body=body,
            openid=openid,
            mch_id=mch_id,
            notify_url=noticePayUrl,
            appid=wxPay.appid,
            model=model,
        )
        try:
            from apps.coffee.models import GoodsTagLevel
            goods_tag = pay_data_value.get("goods_tag")
            user = self.context["request"].user
            today = datetime.date.today()
            tag_level_queryset = GoodsTagLevel.objects.filter(goods_tag=user.mobile, expired_date__gt=today, num__gt=0)
            if tag_level_queryset.exists():
                goods_tag = user.mobile
            #if goods_tag:
            #    goods_tag = pay_data_value.get("goods_tag")
            #    if goods_tag.endswith("_"):
            #        goods_tag += user.mobile
            #     response = wxPay.order.create(trade_type, body, total_fee, noticePayUrl, user_id=openid,
            #                                   out_trade_no=out_trade_no, attach=attach, goods_tag=goods_tag)
            # else:
            #     response = wxPay.order.create(trade_type, body, total_fee, noticePayUrl, user_id=openid,
            #                                   out_trade_no=out_trade_no, attach=attach)
            else:
                pass
                # today = datetime.date.today()
                #if is_workday(today):
                #    goods_tag = user.mobile
                #else:
                #    goods_tag = None
            print(goods_tag, "que ren goods_tag")
            response = wxPay.order.create(trade_type, body, total_fee, noticePayUrl, user_id=openid,
                                          out_trade_no=out_trade_no, attach=attach, goods_tag=goods_tag)
            wx_order_instance.update_order_return_data(response)
            order.goods_tag = goods_tag
            order.save()
        except WeChatPayException as e:
            if e.errmsg:
                print(e.errmsg)
                raise serializers.ValidationError(e.errmsg)
            else:
                print(e.return_msg)
                raise serializers.ValidationError(e.return_msg)
        return wx_order_instance, response

    def update(self, instance, validated_data):
        pass

    class Meta:
        fields = ("user", "orderNo", "model")


# H5微信支付
class H5PaySerializers(BasePaySerializer):
    redirect_url = serializers.CharField(required=True, allow_null=False, label="支付结果页url", help_text="支付结果页url",
                                         write_only=True)

    wxPayInstance = KLBWxPay

    def create(self, validated_data):
        body = "ERROR"
        total_fee = 0
        order = validated_data["orderNo"]
        payResultUrl = validated_data.pop("redirect_url")
        mch_id = KaLaiBaoConfig.mch_id
        noticePayUrl = miniNoticePayUrl
        if validated_data["model"] == "coffee":
            body = "咖啡支付"
            total_fee = order.payment
        self.payData = {"body": body, "total_fee": total_fee, "mch_id": mch_id, "noticePayUrl": noticePayUrl,
                        "trade_type": "MWEB", "attach": 1, "openid": None}
        wx_order_instance, response = super(H5PaySerializers, self).create(validated_data)
        mweb_url = response.get("mweb_url")
        url = urllib.parse.quote(payResultUrl)

        mweb_url += "&redirect_url=" + url
        wx_order_instance.mweb_url = mweb_url
        wx_order_instance.save()
        return wx_order_instance

    class Meta:
        fields = ("user", "out_trade_no", "model", "redirect_url")


# 微信公众号支付
class JsPaySerializer(BasePaySerializer):
    wxPayInstance = KLBWxPay

    def create(self, validated_data):
        body = "ERROR"
        total_fee = 0
        order = validated_data["orderNo"]
        openid = validated_data["user"].wx_user.openid
        mch_id = KaLaiBaoConfig.mch_id
        noticePayUrl = miniNoticePayUrl
        if validated_data["model"] == "coffee":
            body = "咖啡支付"
            total_fee = order.payment
        self.payData = {"body": body, "total_fee": total_fee, "openid": openid, "mch_id": mch_id,
                        "noticePayUrl": noticePayUrl, "trade_type": "JSAPI", "attach": 1}

        wx_order_instance, response = super(JsPaySerializer, self).create(validated_data)
        return wx_order_instance

    class Meta:
        fields = ("user", "orderNo", "model")
